home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
gnu
/
m4-1_0_3.lha
/
m4-1.0.3
/
debug.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-19
|
8KB
|
379 lines
/*
* GNU m4 -- A simple macro processor
* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "m4.h"
/* File for debugging output. */
static FILE *debug;
/* Obstack for trace messages. */
static struct obstack trace;
extern int expansion_level;
/*
* Initialise the debugging module.
*/
void
debug_init (void)
{
debug = stderr;
obstack_init (&trace);
}
/*
* Function to decode the debugging flags OPTS. Used by main (-dXXX)
* and the builtin debugmode ().
*/
int
debug_decode (char *opts)
{
int level;
if (opts == NULL || *opts == '\0')
level = DEBUG_TRACE_DEFAULT;
else
{
for (level = 0; *opts; opts++)
{
switch (*opts)
{
case 'a':
level |= DEBUG_TRACE_ARGS;
break;
case 'e':
level |= DEBUG_TRACE_EXPANSION;
break;
case 'q':
level |= DEBUG_TRACE_QUOTE;
break;
case 't':
level |= DEBUG_TRACE_ALL;
break;
case 'l':
level |= DEBUG_TRACE_LINE;
break;
case 'f':
level |= DEBUG_TRACE_FILE;
break;
case 'p':
level |= DEBUG_TRACE_PATH;
break;
case 'c':
level |= DEBUG_TRACE_CALL;
break;
case 'i':
level |= DEBUG_TRACE_INPUT;
break;
case 'x':
level |= DEBUG_TRACE_CALLID;
break;
case 'V':
level |= DEBUG_TRACE_VERBOSE;
break;
default:
return -1;
}
}
}
/*
* This is to avoid screwing up the trace output due to changes in
* the debug_level.
*/
obstack_free (&trace, obstack_finish (&trace));
return level;
}
/*
* Change the debug output stream to FP.
*/
static void
debug_set_file (FILE *fp)
{
if (debug != NULL && debug != stderr)
fclose (debug);
debug = fp;
}
/*
* Change the debug output to file NAME. If NAME is NULL, debug output
* is reverted to stderr, and if empty debug output is discarded.
* Return TRUE iff the output stream was changed.
*/
boolean
debug_set_output (char *name)
{
FILE *fp;
if (name == NULL)
debug_set_file (stderr);
else if (*name == '\0')
debug_set_file (NULL);
else
{
fp = fopen (name, "a");
if (fp == NULL)
return FALSE;
debug_set_file (fp);
}
return TRUE;
}
/*
* Generic function to do formatted output to the debug output stream.
* Usage as for printf ().
*/
void
debug_print (va_alist)
va_dcl
{
va_list args;
char *fmt;
if (debug != NULL)
{
va_start (args);
fmt = va_arg (args, char *);
vfprintf (debug, fmt, args);
va_end (args);
}
}
/*
* Print a one-line debug message, headed by "m4 debug". Usage as for
* printf ().
*/
void
debug_message (va_alist)
va_dcl
{
va_list args;
char *fmt;
if (debug != NULL)
{
fprintf (debug, "m4 debug: ");
if (debug_level & DEBUG_TRACE_FILE)
fprintf (debug, "%s: ", current_file);
if (debug_level & DEBUG_TRACE_LINE)
fprintf (debug, "%d: ", current_line);
va_start (args);
fmt = va_arg (args, char *);
vfprintf (debug, fmt, args);
va_end (args);
putc ('\n', debug);
}
}
/*
* The rest of this file contains the functions for macro tracing
* output. All tracing output for a macro call is collected on an
* obstack TRACE, and printed whenever the line is complete. This
* prevents tracing output from interfering with other debug messages
* generated by the various builtins.
*/
/*
* Tracing output is formatted here, by a simplified printf-to-obstack
* function trace_format (). Understands only %s, %d, %l (optional left
* quote) and %r (optional right quote).
*/
static void
trace_format (va_alist)
va_dcl
{
va_list args;
char *fmt;
char ch;
int d;
char nbuf[32];
char *s;
int slen;
int maxlen;
va_start (args);
fmt = va_arg (args, char *);
while (TRUE)
{
while ((ch = *fmt++) != '\0' && ch != '%')
obstack_1grow (&trace, ch);
if (ch == '\0')
break;
maxlen = 0;
switch (*fmt++)
{
case 'S':
maxlen = max_debug_argument_length;
/* fall through */
case 's':
s = va_arg (args, char *);
break;
case 'l':
s = (debug_level & DEBUG_TRACE_QUOTE) ? lquote : "";
break;
case 'r':
s = (debug_level & DEBUG_TRACE_QUOTE) ? rquote : "";
break;
case 'd':
d = va_arg (args, int);
sprintf (nbuf, "%d", d);
s = nbuf;
break;
default:
s = "";
break;
}
slen = strlen (s);
if (maxlen == 0 || maxlen > slen)
obstack_grow (&trace, s, slen);
else
{
obstack_grow (&trace, s, maxlen);
obstack_grow (&trace, "...", 3);
}
}
va_end (args);
}
/*
* Format the standard header attached to all tracing output lines.
*/
static void
trace_header (int id)
{
trace_format ("m4trace:");
if (debug_level & DEBUG_TRACE_FILE)
trace_format ("%s:", current_file);
if (debug_level & DEBUG_TRACE_LINE)
trace_format ("%d:", current_line);
trace_format (" -%d- ", expansion_level);
if (debug_level & DEBUG_TRACE_CALLID)
trace_format ("id %d: ", id);
}
/*
* Print current tracing line, and clear the obstack.
*/
static void
trace_flush (void)
{
char *line;
obstack_1grow (&trace, '\0');
line = obstack_finish (&trace);
debug_print ("%s\n", line);
obstack_free (&trace, line);
}
/*
* Do pre-argument-collction tracing for macro NAME. Used from
* expand_macro ().
*/
void
trace_prepre (char *name, int id)
{
trace_header (id);
trace_format ("%s ...", name);
trace_flush ();
}
/*
* Format the parts of a trace line, that can be made before the macro
* is actually expanded. Used from expand_macro ().
*/
void
trace_pre (char *name, int id, int argc, token_data **argv)
{
int i;
const builtin *bp;
trace_header (id);
trace_format ("%s", name);
if (argc > 1 && (debug_level & DEBUG_TRACE_ARGS))
{
trace_format ("(");
for (i = 1; i < argc; i++)
{
if (i != 1)
trace_format (", ");
switch (TOKEN_DATA_TYPE (argv[i]))
{
case TOKEN_TEXT:
trace_format ("%l%S%r", TOKEN_DATA_TEXT (argv[i]));
break;
case TOKEN_FUNC:
bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv[i]));
if (bp == NULL)
internal_error ("builtin not found in builtin table! (trace_pre ())");
trace_format ("<%s>", bp->name);
break;
default:
internal_error ("Bad token data type (trace_pre ())");
break;
}
}
trace_format (")");
}
if (debug_level & DEBUG_TRACE_CALL)
{
trace_format (" -> ???");
trace_flush ();
}
}
/*
* Format the final part of a trace line and print it all. Used from
* expand_macro ().
*/
void
trace_post (char *name, int id, int argc, token_data **argv, char *expanded)
{
if (debug_level & DEBUG_TRACE_CALL)
{
trace_header (id);
trace_format ("%s%s", name, (argc > 1) ? "(...)" : "");
}
if (expanded && (debug_level & DEBUG_TRACE_EXPANSION))
trace_format (" -> %l%S%r", expanded);
trace_flush ();
}